Introduction to Bar Layer
What is a bar layer?
A bar layer is made up of rectangular bars. They are useful when the data has a categorical (dimension) field against a measure field. The alignment (horizontal / vertical) of the bars are determined from which type of variable is mapped to x and y axis.
Example
const { muze, getDataFromSearchQuery } = viz;
const data = getDataFromSearchQuery();
muze
.canvas()
.rows(["Horsepower"])
.columns(["Origin"])
.color("Cylinders")
.data(data)
.mount("#chart");
Although we have not mentioned what kind of chart to be displayed, Muze based on the type of field getting assigned to rows and columns creates a visualization with one layer of bar mark.
Muze can render various kinds of bar charts based on the configurations.
Creating a horizontal and vertical bar chart
Vertical bar chart
Example
const { muze, getDataFromSearchQuery } = viz;
const data = getDataFromSearchQuery();
muze
.canvas()
.rows(["Miles_per_Gallon"])
.columns(["Origin"])
.data(data)
.mount("#chart");
Horizontal bar chart
Keeping the above chart intact if we just alter the rows and columns fields we get a horizontal bar chart.
Example
const { muze, getDataFromSearchQuery } = viz;
const data = getDataFromSearchQuery();
muze
.canvas()
.columns(["Miles_per_Gallon"])
.rows(["Origin"])
.data(data)
.mount("#chart");
Creating a stacked and grouped bar chart
Stacked bar chart
Adding a color encoding to the first chart will transform it into a stacked bar chart. The bars are stacked based on the value of the field assigned to color encoding channel. But we wont be doing that directly, as the previous data is not appropriate for stack column. We have calculated a new variable which displays the count of cars per region (Origin) by Cylinders using DataModel's operator. We will be using this data to render the stacked bar chart.
Example
const { muze, getDataFromSearchQuery } = viz;
const data = getDataFromSearchQuery();
let dm = new DataModel(data);
const carCountDM = dm.calculateVariable(
{
name: "carCount",
type: "measure",
},
["Name"],
() => 1,
);
muze
.canvas()
.rows(["carCount"])
.columns(["Origin"])
.color("Cylinders")
.data(carCountDM)
.mount("#chart");
NOTE: Not all kind of data are suitable for stacking. In the above we had to create a new field so that stacking makes sense. If your data already have a field for which stacking makes sense, there is no need of transformation.
Grouped bar chart
When we created a stacked chart, we just added a field to color encoding channel. Internally Muze took some decisions and rendered a stacked bar chart. stack is a transformation Muze choose by default to render a chart when a field is assigned to color, shape or size. We have to be explicit when we need a group (or dodge) transformed chart.
Example
const { muze, getDataFromSearchQuery } = viz;
const data = getDataFromSearchQuery();
muze
.canvas()
.columns(["Miles_per_Gallon"])
.rows(["Origin"])
.color("Cylinders")
.layers([
{
mark: "bar",
transform: { type: "group" }, // By default stack transform is selected
},
])
.data(data)
.mount("#chart");
NOTE: In the stacked bar example we had not called the layers method which allowed Muze to push the default layer configuration with default transform type which is stack
Creating a range bar chart
To create a range bar chart, we can use the x and x0 encoding to define the width of the bars and y and y0 to define the height of the bars. If we map these encodings to different measures, then it will plot a range bar chart.
For example, here we are plotting a range bar showing the temperature range. We are taking the max. weight and min. weight measure, and setting it to the columns array. But as we have to show multiple measures in a single axis, we will have to use share operator of Muze. share operator allows you to plot multiple measures in a single axis.
Example
const { muze, getDataFromSearchQuery } = viz;
const data = getDataFromSearchQuery();
let dm = new DataModel(data);
const share = muze.Operators.share;
// Min value of weight for a group
dm = dm.calculateVariable(
{
name: "Min Weight",
type: "measure",
defAggFn: "min",
},
["Weight_in_lbs"],
(val) => val,
);
// Max value of weight for a group
dm = dm.calculateVariable(
{
name: "Max Weight",
type: "measure",
defAggFn: "max",
},
["Weight_in_lbs"],
(val) => val,
);
muze
.canvas()
.columns([share("Max Weight", "Min Weight")])
.rows(["Year"])
.layers([
{
mark: "bar",
encoding: {
x: "Max Weight",
x0: "Min Weight",
color: { value: () => "#ff9800" },
},
},
])
.config({
axes: {
y: {
name: "Weight",
},
},
})
.data(dm)
.mount("#chart");
Creating a heatmap using bar layer and color encoding
For creating a heatmap, plot two dimensions with mark bar and shrink the gaps (padding) between the bars by setting the padding to 0.
Example
const { muze } = viz;
const DataModel = muze.DataModel;
const data = `Month,Name,Sales
Jan,Michael,"44238"
Feb,Michael,"37640"
Mar,Michael,"47380"
May,Michael,"22413"
Jun,Michael,"23191"
Jul,Michael,"20112"
Oct,Michael,"7651"
Nov,Michael,"5630"
Jan,Stanley,"44770"
Feb,Stanley,"43900"
Mar,Stanley,"32476"
May,Stanley,"21143"
Jun,Stanley,"32632"
Jul,Stanley,"29548"
Oct,Stanley,"38960"
Nov,Stanley,"37880"
Jan,Packer,"11634"
Feb,Packer,"4818"
Mar,Packer,"24329"
May,Packer,"20134"
Jun,Packer,"22562"
Jul,Packer,"3467"
Oct,Packer,"9812"
Nov,Packer,"8832"`;
const schema = [
{
name: "Month",
type: "dimension",
},
{
name: "Name",
type: "dimension",
},
{
name: "Sales",
type: "measure",
},
];
let dm = new DataModel(await DataModel.loadData(data, schema));
muze
.canvas()
.rows(["Name"])
.columns(["Month"])
.color({
// Color encoding
field: "Sales",
})
.layers([
{
// For drawing the heatmap background
mark: "bar",
},
{
// For drawing the text
mark: "text",
encoding: {
text: {
field: "Sales",
formatter: (value) => `${(value.rawValue / 1000).toFixed(1)}k`, // Formats the value of text
},
color: {
value: () => "#fff",
},
},
interactive: false,
},
])
.config({
axes: {
// With bar encoding, it normally draws a bar chart without padding. Here its forcefully made zero
x: {
padding: 0,
},
y: {
padding: 0,
},
},
legend: {
color: {
step: true,
range: ["#BBF6F0", "#85ECE1", "#50C0B5", "#12877B", "#005F56"],
},
},
})
.title("Heatmap", { position: "top", align: "center" })
.subtitle("Sales per month for each sales person", {
position: "top",
align: "center",
})
.data(dm)
.width(750)
.height(450)
.mount("#chart");
Creating a heatmap with time axis
We can also create a heatmap chart with time axis just by setting a temporal field in columns or rows.
Example
const { muze, getDataFromSearchQuery } = viz;
const data = getDataFromSearchQuery();
const dm = data.calculateVariable(
{
name: "Count",
type: "measure",
defAggFn: "count",
},
["Origin"],
() => 1,
);
muze
.canvas()
.rows(["Origin"])
.columns(["Year"])
.color({
// Color encoding
field: "Count",
})
.config({
axes: {
// With bar encoding, it normally draws a bar chart without padding.
// Here its forcefully made zero
x: {
padding: 0,
},
y: {
padding: 0,
},
},
legend: {
color: {
step: true,
range: ["#BBF6F0", "#85ECE1", "#50C0B5", "#12877B", "#005F56"],
},
},
})
.title("Heatmap", { position: "top", align: "center" })
.subtitle("Number of cars manufactured in each Origin by Year", {
position: "top",
align: "center",
})
.data(dm)
.width(750)
.height(300);